package com.zxyankh.leetcode.question.chinese;

import java.util.*;

/**
 * 给定一个数组 candidates 和一个目标数 target ，找出 candidates 中所有可以使数字和为 target 的组合。
 * <p>
 * candidates 中的每个数字在每个组合中只能使用一次。
 * <p>
 * 说明：
 * <p>
 * 所有数字（包括目标数）都是正整数。
 * 解集不能包含重复的组合。 
 * 示例 1:
 * <p>
 * 输入: candidates = [10,1,2,7,6,1,5], target = 8,
 * 所求解集为:
 * [
 * [1, 7],
 * [1, 2, 5],
 * [2, 6],
 * [1, 1, 6]
 * ]
 * 示例 2:
 * <p>
 * 输入: candidates = [2,5,2,1,2], target = 5,
 * 所求解集为:
 * [
 *   [1,2,2],
 *   [5]
 * ]
 * <p>
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/combination-sum-ii
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 *
 * @author zxyAnkh
 */
public class No40 {

    public List<List<Integer>> combinationSum2(int[] candidates, int target) {
        Arrays.sort(candidates);
        Set<List<Integer>> result = new HashSet<>();
        for (int i = 0; i < candidates.length; i++) {
            int n = target - candidates[i];
            if (n == 0) {
                result.add(Collections.singletonList(candidates[i]));
            } else if (n > 0) {
                List<Integer> list = new ArrayList<>();
                list.add(candidates[i]);
                combinationSum(result, list, i, candidates, n);
            }
        }
        return new ArrayList<>(result);
    }

    private void combinationSum(Set<List<Integer>> result, List<Integer> list, int i, int[] candidates, int target) {
        for (int j = i + 1; j < candidates.length; j++) {
            int n = target - candidates[j];
            if (n == 0) {
                List<Integer> l = new ArrayList<>(list);
                l.add(candidates[j]);
                result.add(l);
            } else if (n > 0) {
                List<Integer> l = new ArrayList<>(list);
                l.add(candidates[j]);
                combinationSum(result, l, j, candidates, n);
            }
        }
    }

}
